package com.netintech.process.service;

import com.netintech.common.utils.DateUtils;
import com.netintech.common.utils.SecurityUtils;
import com.netintech.common.utils.StringUtils;
import com.netintech.process.todoitem.domain.BizTodoItem;
import com.netintech.process.todoitem.service.IBizTodoItemService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 流程通用封装类
 */
@Service("processCommonService")
@Transactional
public class ProcessCommonService {

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private IBizTodoItemService todoService;

    @Autowired
    private TaskService taskService;

    private static final String HAVE_NOT_HANDLE = "0";

    private static final String HAVE_HANDLE = "1";

    /**
     * 提交申请
     * @param itemName 待办标题
     * @param itemContent 待办事项
     * @param entityId 业务类ID
     * @param applyUserId 申请人id
     * @param moduleKey 流程模型key
     * 提交申请业务类，在调用提交申请方法时，还需要在业务类中设置applyId、applyTime、processInstanceId,实现双向绑定
     * @return
     */
    public ProcessInstance submitApply(String itemName, String itemContent, Long entityId, String applyUserId, String moduleKey, Map<String, Object> variables){
        String businessKey = entityId.toString(); // 实体类 ID，作为流程的业务 key
        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId(applyUserId);
        ProcessInstance processInstance = runtimeService // 启动流程时设置业务key
                .startProcessInstanceByKey(moduleKey, businessKey, variables);
        // 下一节点处理人待办事项
        todoService.insertTodoItem(itemName, itemContent, processInstance.getProcessInstanceId(), moduleKey);
        return processInstance;
    }

    /**
     * 完成任务
     */
    public void complete(String itemName, String itemContent, String instanceId, boolean saveEntityBoolean, String moduleKey, String taskId, Map<String, Object> variables, String comment){
        if (saveEntityBoolean) {
            identityService.setAuthenticatedUserId(SecurityUtils.getUserIdString());
        }
        if(StringUtils.isNotBlank(comment)){
            taskService.addComment(taskId, instanceId, comment);
        }
        // 只有签收任务，act_hi_taskinst 表的 assignee 字段才不为 null
        taskService.claim(taskId, SecurityUtils.getUserIdString());
        taskService.complete(taskId, variables);
        // 更新待办事项状态
        BizTodoItem query = new BizTodoItem();
        query.setTaskId(taskId);
        // 考虑到候选用户组，会有多个 todoitem 办理同个 task
        List<BizTodoItem> updateList = CollectionUtils.isEmpty(todoService.selectBizTodoItemList(query)) ? null : todoService.selectBizTodoItemList(query);
        for (BizTodoItem update: updateList) {
            // 找到当前登录用户的 todoitem，置为已办
            if (update.getTodoUserId().equals(SecurityUtils.getUserIdString())) {
                update.setIsView(HAVE_HANDLE);//已查看
                update.setIsHandle(HAVE_HANDLE);//已处理
                update.setHandleUserId(SecurityUtils.getUserIdString());
                update.setHandleUserName(SecurityUtils.getLoginUser().getUser().getNickName());
                update.setHandleTime(LocalDateTime.now());
                todoService.updateBizTodoItem(update);
            } else {
                todoService.deleteBizTodoItemById(update.getId()); // 删除候选用户组其他 todoitem
            }
        }
        // 下一节点处理人待办事项
        todoService.insertTodoItem(itemName, itemContent, instanceId, moduleKey);
    }

    /**
     * 根据任务Id,显示审核页面和业务id
     * @param taskId
     * @return
     */
    public Map<String, String> showAuditPage(String taskId){
        Map<String, String> map = new HashMap<>(2);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String processInstanceId = task.getProcessInstanceId();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        map.put("pageName", task.getTaskDefinitionKey().substring(0, 1).toUpperCase() + task.getTaskDefinitionKey().substring(1));
        map.put("entityId", processInstance.getBusinessKey());
        return map;
    }
}
